package models

import (
	"fmt"
	"gitchina/kly_service/data"
	"gitchina/kly_service/errors"
	"gitchina/kly_service/util"
	"strconv"
	"strings"
)

var area_map = make(map[string]string)
var province_map = make(map[string]string)
var city_map = make(map[string]string)
var county_map = make(map[string]string)
var province_city_map = make(map[string]map[string]string)
var city_county_map = make(map[string]map[string]string)
var invoiceCorp_map = make(map[string]InvoiceCorp)

type Logistics struct{}

type Position struct {
	Id   int     `json:"id"`
	Lng  float32 `json:"lng"`
	Lat  float32 `json:"lat"`
	Time string  `json:"time"`
}

type TransportLog struct {
	WaybillId ID         `json:"waybill_id"`
	Offset    int        `json:"offset"`
	Pos       []Position `json:"position_list"`
}

func LogisticsInit() {
	var city_list_map map[string]string
	var county_list_map map[string]string
	var repo data.LogisticsRepo
	for _, list := range repo.GetAllAreas() {
		area_map[list[0].(string)] = list[1].(string)
		if idStr, ok := list[0].(string); ok {
			if id, err := strconv.Atoi(idStr); err == nil {
				name, _ := list[1].(string)
				if id%10000 == 0 {
					province_map[idStr] = name
					city_list_map = make(map[string]string)
					province_city_map[idStr] = city_list_map
				} else {
					if id%100 == 0 || strings.HasSuffix(name, "市") {
						city_map[idStr] = name
						city_list_map[idStr] = name
						if id%100 == 0 {
							county_list_map = make(map[string]string)
							city_county_map[idStr] = county_list_map
						}
					} else {
						county_map[idStr] = name
						county_list_map[idStr] = name
					}
				}
			}
		}
	}
	province_map["0"] = "全国"
	city_map["0"] = "全国"
	county_map["0"] = "全国"

	for _, list := range repo.GetInvoiceCorps() {
		invoiceCorp_map[strconv.Itoa(list.Id)] = InvoiceCorp{
			Id:     list.Id,
			AreaId: list.AreaId,
			Name:   list.Name,
			Addr:   list.Addr,
		}
	}
}

func (l Logistics) GetAreaMap(areaId string) (areaMap map[string]string) {
	if id, err := strconv.Atoi(areaId); err == nil {
		if id == -1 {
			areaMap = area_map
		} else if id == 0 {
			areaMap = province_map
		} else if id%10000 == 0 {
			areaMap, _ = province_city_map[areaId]
		} else if id%100 == 0 {
			areaMap, _ = city_county_map[areaId]
		}
	}
	return
}

func (l Logistics) GetProvinceList() map[string]string {
	return province_map
}

func (l Logistics) GetCityList(provinceId string) map[string]string {
	m, _ := province_city_map[provinceId]
	return m
}

func (l Logistics) GetProvinceName(provinceId string) string {
	p, _ := l.GetProvinceList()[provinceId]
	return p
}

func (l Logistics) GetCityName(cityId string) string {
	c, _ := city_map[cityId]
	return c
}

func (l Logistics) GetCountyName(countyId string) string {
	c, _ := county_map[countyId]
	return c
}

func (l Logistics) GetAreaName(id int) string {
	var areaName string
	if id%10000 == 0 {
		areaName = l.GetProvinceList()[strconv.Itoa(id)]
	} else if id%100 == 0 {
		areaName = l.GetCityName(strconv.Itoa(id))
	} else {
		areaName = l.GetCountyName(strconv.Itoa(id))
	}
	return areaName
}

func (l Logistics) GetAreaID(name string) string {
	var repo data.LogisticsRepo
	return repo.GetAreaID(name)
}

func (l Logistics) GetAreaFullName(id int) string {
	var areaName string
	if id%10000 == 0 {
		areaName = l.GetProvinceName(strconv.Itoa(id))
	} else if id%100 == 0 {
		provinceName := l.GetProvinceName(strconv.Itoa(id - id%10000))
		areaName = provinceName + l.GetCityName(strconv.Itoa(id))
	} else {
		provinceName := l.GetProvinceName(strconv.Itoa(id - id%10000))
		cityName := l.GetCityName(strconv.Itoa(id - id%100))
		areaName = provinceName + cityName + l.GetCountyName(strconv.Itoa(id))
	}
	return areaName
}

func (l Logistics) AddTransportLog(rq *TransportLog) (addLogState int, err error) {
	var id int64
	_, _, _, id, err = rq.WaybillId.Decode()
	if err != nil {
		err = errors.New(errors.MSG_Order_Invalid_Waybill)
	} else {
		if len(rq.Pos) > 0 {
			var orderRepo data.OrderRepo
			if state, updTime, err := orderRepo.GetWaybillState(int(id)); err == nil {
				if state >= 2 && state <= 6 {
					if err = l.addTransportLog(int(id), rq); err != nil {
						util.GetLogger().Error("[model-AddTransportLog] - error:%s", err.Error())
						err = errors.New(errors.MSG_Logi_Add_Transport_Log_Error)
					}
					addLogState = 1 //recording
				} else {
					if strings.Compare(rq.Pos[0].Time, updTime) < 0 {
						if err = l.addTransportLog(int(id), rq); err != nil {
							util.GetLogger().Error("[model-AddTransportLog] - error:%s", err.Error())
							err = errors.New(errors.MSG_Logi_Add_Transport_Log_Error)
						}
						addLogState = 1 //recording
					} else {
						addLogState = 2 //waybill has not started or completed, stop recording
					}

				}
			} else {
				util.GetLogger().Error("[model-AddTransportLog] - error:%s", err.Error())
				err = errors.New(errors.MSG_Logi_Add_Transport_Log_Error)
			}
		} else {
			err = errors.New(errors.MSG_Logi_Invalid_Transport_Log)
		}
	}
	return
}

func (l Logistics) GetLastTransportLog(waybillId ID) (rs TransportLog) {
	var repo data.LogisticsRepo
	if _, _, _, id, err := waybillId.Decode(); err == nil {
		if dto, err := repo.GetLastTransportLog(int(id)); err == nil {
			pos := Position{
				Lng:  dto.Lng,
				Lat:  dto.Lat,
				Time: dto.Time,
				Id:   dto.Id,
			}
			rs = TransportLog{WaybillId: waybillId, Pos: []Position{pos}, Offset: pos.Id}
		} else {
			util.GetLogger().Error("[model-GetTransportLog] - error:%s", err.Error())
		}
	}
	return
}

func (l Logistics) GetTransportLogs(waybillId ID, offset int) (rs TransportLog) {
	var repo data.LogisticsRepo
	if _, _, _, id, err := waybillId.Decode(); err == nil {
		offset := 0
		if list, err := repo.GetTransportLogs(int(id), offset); err == nil {
			pos := make([]Position, len(list))
			for idx, dto := range list {
				pos[idx] = Position{
					Lng:  dto.Lng,
					Lat:  dto.Lat,
					Time: dto.Time,
					Id:   dto.Id,
				}
			}
			if len(list) > 0 {
				offset = list[len(list)-1].Id
			}
			rs = TransportLog{WaybillId: waybillId, Pos: pos, Offset: offset}
		} else {
			util.GetLogger().Error("[model-GetTransportLog] - error:%s", err.Error())
		}
	}
	return
}

func (l Logistics) chooseArea(province, city, county int) string {
	var area string
	if county == 0 {
		if city == 0 {
			area = fmt.Sprintf("%d", province)
		} else {
			area = fmt.Sprintf("%d", city)
		}
	} else {
		area = fmt.Sprintf("%d", county)
	}
	return area
}

func (l Logistics) addTransportLog(waybillId int, rq *TransportLog) error {
	var repo data.LogisticsRepo
	transportList := make([]data.TransportDto, len(rq.Pos))
	for idx, pos := range rq.Pos {
		transportList[idx] = data.TransportDto{
			WaybillId: int(waybillId),
			Lng:       pos.Lng,
			Lat:       pos.Lat,
			Time:      pos.Time,
		}
	}
	return repo.AddTransportLog(transportList)

	// if err = repo.AddTransportLog(transportList); err != nil {
	// 	util.GetLogger().Error("[model-AddTransportLog] - error:%s", err.Error())
	// 	err = errors.New(errors.MSG_Logi_Add_Transport_Log_Error)
	// }
}
